﻿using DTcms.Core.Common.Emum;
using DTcms.Core.Common.Extensions;
using DTcms.Core.Common.Helper;
using DTcms.Core.IServices;
using DTcms.Core.IServices.WeChatPay;
using DTcms.Core.Model.WeChatPay;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;

namespace DTcms.Core.Services.WeChatPay
{
    /// <summary>
    /// 微信支付接口实现
    /// </summary>
    public class WeChatPayExecute : WeChatPayBase, IWeChatPayExecute
    {
        private readonly IHttpContextAccessor _httpContextAccessor;
        public WeChatPayExecute(IHttpContextAccessor httpContextAccessor, ISitePaymentService sitePaymentService) : base(sitePaymentService)
        {
            _httpContextAccessor = httpContextAccessor;
        }

        /// <summary>
        /// 扫码下单支付
        /// </summary>
        public async Task<WeChatPayNativeParamDto> NativePayAsync(WeChatPayDto modelDto)
        {
            //取得微信支付账户
            var wxAccount = await GetAccountAsync(modelDto.PaymentId);

            //赋值下单实体(注意附加数据为站点ID)
            WeChatPayBodyDto model = new WeChatPayBodyDto
            {
                AppId = wxAccount.AppId,
                MchId = wxAccount.MchId,
                Description = modelDto.Description,
                OutTradeNo = modelDto.OutTradeNo,
                NotifyUrl = $"{_httpContextAccessor.HttpContext.Request.Scheme}://{_httpContextAccessor.HttpContext.Request.Host}{wxAccount.NotifyUrl}/transactions/{modelDto.PaymentId}",
                Amount = new Amount { Total = (int)(modelDto.Total * 100), Currency = "CNY" }
            };
            var url = WeChatPayConfig.NativePayUrl;
            var content = model.ToJson();
            var auth = BuildAuth(url, "POST", content, wxAccount.MchId, wxAccount.CertPath, wxAccount.MchId);
            //发送POST请求
            ICollection<KeyValuePair<string, string>> headers = new List<KeyValuePair<string, string>>();
            headers.Add(new KeyValuePair<string, string>("Authorization", $"WECHATPAY2-SHA256-RSA2048 {auth}"));
            headers.Add(new KeyValuePair<string, string>("User-Agent", "Unknown"));
            headers.Add(new KeyValuePair<string, string>("Accept", "application/json"));
            var (statusCode, reHeaders, reBody) = RequestHelper.Post(url, headers, content);
            if (statusCode != 200)
            {
                throw new ResponseException($"微信下单失败，错误代码：{statusCode},{reBody}");
            }
            var codeUrl = JsonHelper.ToJson<WeChatPayNativeResultDto>(reBody).CodeUrl;
            //生成Base64图片
            var codeData = QRCodeHelper.GenerateToString(codeUrl);
            return new WeChatPayNativeParamDto { CodeData = codeData };
        }

        #region 私有辅助方法
        /// <summary>
        /// 生成头部Authorization
        /// </summary>
        private string BuildAuth(string url, string method, string body, string mchId, string certPath, string certPwd)
        {
            var uri = new Uri(url).PathAndQuery;
            var timestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString();
            var nonce = Guid.NewGuid().ToString("N");
            var message = $"{method}\n{uri}\n{timestamp}\n{nonce}\n{body}\n";
            var certificate2 = new X509Certificate2(certPath, certPwd, X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet);
            var signature = SHA256WithRSA.Sign(certificate2.GetRSAPrivateKey(), message);
            return $"mchid=\"{mchId}\",nonce_str=\"{nonce}\",timestamp=\"{timestamp}\",serial_no=\"{certificate2.GetSerialNumberString()}\",signature=\"{signature}\"";
        }
        #endregion
    }
}
